package cn.xinfei.xdecision.common.service.component.dependency.impl;

import cn.xinfei.xdecision.common.dao.component.dependency.EngineNodeComponentRelMapper;
import cn.xinfei.xdecision.common.model.common.PageResult;
import cn.xinfei.xdecision.common.model.common.PageResultNew;
import cn.xinfei.xdecision.common.model.common.ResponseEntityDto;
import cn.xinfei.xdecision.common.model.common.requestParam.AssemblyRuleCodeReq;
import cn.xinfei.xdecision.common.model.component.dependency.EngineNodeComponentRel;
import cn.xinfei.xdecision.common.model.component.dependency.resp.DecisionComponentDependencyResp;
import cn.xinfei.xdecision.common.model.datax.datainterface.v2.VariableVO;
import cn.xinfei.xdecision.common.model.enginex.po.EngineVersion;
import cn.xinfei.xdecision.common.service.component.ComponentCommonService;
import cn.xinfei.xdecision.common.service.component.dependency.EngineNodeComponentRelService;
import cn.xinfei.xdecision.common.service.datax.datamanage.v2.VariableService;
import cn.xinfei.xdecision.common.service.enginex.EngineNodeService;
import cn.xinfei.xdecision.common.service.enginex.EngineVersionService;
import cn.xinfei.xdecision.common.utils.constant.SysConstant;
import cn.xinfei.xdecision.common.utils.enums.enginex.EngineStatusEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.EngineVersionStatusEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.NodeTypeEnum;
import cn.xinfei.xdecision.common.utils.exception.ApiException;
import cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum;
import cn.xinfei.xdecision.common.utils.util.FutureUtils;
import cn.xinfei.xdecision.common.utils.util.PageUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum.PARAMS_EXCEPTION;

@Service
public class EngineNodeComponentRelServiceImpl extends ServiceImpl<EngineNodeComponentRelMapper, EngineNodeComponentRel> implements EngineNodeComponentRelService {

    @Resource
    private EngineNodeService engineNodeService;

    @Resource
    private List<ComponentCommonService> componentCommonServices;

    @Resource
    private EngineNodeComponentRelMapper engineNodeComponentRelMapper;

    @Resource
    private VariableService variableService;

    @Resource
    private EngineVersionService engineVersionService;

    @Resource(name = "dependencyAsyncExecutor")
    private ExecutorService bizProcessorThreadPool;


    @Override
    public ResponseEntityDto<PageResultNew<DecisionComponentDependencyResp>> getRelByComponentCode(AssemblyRuleCodeReq assemblyRuleCodeReq) {
        //分页
        PageMethod.startPage(assemblyRuleCodeReq.getPageNo(), assemblyRuleCodeReq.getPageSize());
        List<DecisionComponentDependencyResp> dependencyRespList = engineNodeComponentRelMapper.listByRuleCodes(assemblyRuleCodeReq.getRuleCodes());
        dependencyRespList.forEach(item -> item.setEngineVersionStatusDesc(
                Objects.requireNonNull(EngineVersionStatusEnum.get(item.getEngineVersionStatus())).getName())
                .setVersionNoDesc("V" + item.getVersionNo())
                .setEngineVersionDesc("V" + item.getEngineVersion()));
        return PageResultNew.success(dependencyRespList);
    }

    @Override
    public List<EngineNodeComponentRel> getRelByComponentCode(List<String> componentCodes) {
        if (CollectionUtils.isEmpty(componentCodes)) {
            return new ArrayList<>();
        }
        return this.list(new LambdaQueryWrapper<EngineNodeComponentRel>()
                .in(EngineNodeComponentRel::getComponentCode, componentCodes));
    }

    @Override
    public Boolean saveOrUpdateRel(EngineNodeComponentRel engineNodeComponentRel) {
        if (Objects.isNull(engineNodeComponentRel) ||
                StringUtils.isEmpty(engineNodeComponentRel.getComponentCode()) ||
                Objects.isNull(engineNodeComponentRel.getComponentVersionNo()) ||
                StringUtils.isEmpty(engineNodeComponentRel.getEngineNodeCode()) ||
                Objects.isNull(engineNodeComponentRel.getEngineVersionId())) {
            return Boolean.FALSE;
        }
        return this.saveOrUpdate(engineNodeComponentRel);
    }

    @Override
    public ResponseEntityDto<PageResult<List<DecisionComponentDependencyResp>, EngineNodeComponentRel>> getRelByVarCode(AssemblyRuleCodeReq assemblyRuleCodeReq) {
        List<String> varCodes = assemblyRuleCodeReq.getVarCodes();
        if (CollectionUtils.isEmpty(assemblyRuleCodeReq.getVarCodes())) {
            throw new ApiException(PARAMS_EXCEPTION);
        }
        if (varCodes.size() > 200) {
            throw new ApiException(ErrorCodeEnum.SIZE_TOO_LONG);
        }
        List<DecisionComponentDependencyResp> allVarDependencies = new CopyOnWriteArrayList<>();
        List<Future<Void>> allFutureList = Lists.newArrayList();
        componentCommonServices.forEach(service -> allFutureList.add(CompletableFuture.runAsync(() -> {
            //获取所有变量对应的组件code
            List<DecisionComponentDependencyResp> componentCodeByVarCodes = service.getComponentCodeByVarCodes(varCodes);
            if (CollectionUtils.isEmpty(componentCodeByVarCodes)) {
                return;
            }
            List<String> componentCodeList = componentCodeByVarCodes.stream()
                    .map(DecisionComponentDependencyResp::getComponentCode).distinct().collect(Collectors.toList());
            //200一组分页查询
            List<List<String>> componentCodeGroups = PageUtils.splitList(componentCodeList, PageUtils.GROUP_SIZE);
            componentCodeGroups.forEach(componentCodes -> {
                AssemblyRuleCodeReq req = new AssemblyRuleCodeReq();
                req.setRuleCodes(componentCodes);
                req.setPageSize(PageUtils.GROUP_SIZE);
                //获取依赖关系
                ResponseEntityDto<PageResultNew<DecisionComponentDependencyResp>> dependencyByComponentCode =
                        getRelByComponentCode(req);
                List<DecisionComponentDependencyResp> dependencyRespList = dependencyByComponentCode.getData().getKlist();
                if (!CollectionUtils.isEmpty(dependencyRespList)) {
                    Map<String, List<DecisionComponentDependencyResp>> collect = dependencyRespList.stream()
                            .collect(Collectors.groupingBy(x -> x.getComponentCode() + "_" + x.getVersionNo()));
                    componentCodeByVarCodes.forEach(x -> {
                        //如果变量所对应的组件没有被引擎引用，则过滤掉
                        List<DecisionComponentDependencyResp> dependencies = collect.get(x.getComponentCode() + "_" + x.getVersionNo());
                        if (!CollectionUtils.isEmpty(dependencies)) {
                            dependencies.forEach(item -> item.setComponentType(x.getComponentType())
                                    .setVersionNo(x.getVersionNo()));
                            allVarDependencies.addAll(dependencies);
                        }
                    });
                }
            });
        }, bizProcessorThreadPool)));
        allFutureList.forEach(x -> FutureUtils.futureGet(x, ErrorCodeEnum.VAR_REL_ERROR));
        PageInfo<EngineNodeComponentRel> pageInfo = new PageInfo<>();
        pageInfo.setTotal(allVarDependencies.size());
        //内存分页
        return PageResult.success(
                PageUtils.startPage(allVarDependencies, assemblyRuleCodeReq.getPageNum(), assemblyRuleCodeReq.getPageSize()), pageInfo);
    }

    @Override
    public Integer removeRel(List<EngineNodeComponentRel> list) {
        if (CollectionUtils.isEmpty(list)) {
            return SysConstant.ZERO.intValue();
        }
        return engineNodeComponentRelMapper.batchUpdateDependency(list);
    }

    @Override
    public List<VariableVO> searchVariablesByEngineVersionId(EngineVersion engineVersion) {
        Set<String> varCodes = new HashSet<>();
        //查询当前节点的全部变量
        List<String> fieldCodes = engineNodeService.getFieldCodesByEngineVersionId(engineVersion.getId());
        if (!CollectionUtils.isEmpty(fieldCodes)) {
            varCodes.addAll(fieldCodes.stream().map(codes -> Sets.newHashSet(codes.split(SysConstant.COMMA)))
                    .flatMap(Set::stream).collect(Collectors.toSet()));
        }
        //前驱
        recursionPrecursorVarCodes(engineVersion.getEngineCode(), varCodes);
        //后继
        recursionSuccessorVarCodes(engineVersion.getEngineCode(), varCodes);
        if (CollectionUtils.isEmpty(varCodes)) {
            return Collections.emptyList();
        }
        //200一组分页查询
        List<List<String>> varCodeGroups = PageUtils.splitList(new ArrayList<>(varCodes), PageUtils.GROUP_SIZE);
        List<VariableVO> variableVOS = new CopyOnWriteArrayList<>();
        List<Future<Void>> allFutureList = Lists.newArrayList();
        varCodeGroups.forEach(varCodeGroup -> allFutureList.add(CompletableFuture.runAsync(() ->
                variableVOS.addAll(variableService.fineVarVosByVarCodes(varCodeGroup)), bizProcessorThreadPool)));
        allFutureList.forEach(x -> FutureUtils.futureGet(x, ErrorCodeEnum.VAR_ERROR));
        return variableVOS;
    }

    @Override
    public List<DecisionComponentDependencyResp> listByEngineNodeCodes(List<String> engineNodes, Integer componentType, Integer status) {
        return engineNodeComponentRelMapper.listByEngineNodeCodes(engineNodes, componentType, status);
    }

    /**
     * 递归查找当前后继引擎变量集合
     */
    private void recursionSuccessorVarCodes(String componentCode, Set<String> varCodes) {
        //查询子引擎
        List<EngineNodeComponentRel> list = this.list(
                new LambdaQueryWrapper<EngineNodeComponentRel>()
                        .select(EngineNodeComponentRel::getComponentCode)
                        .likeRight(EngineNodeComponentRel::getEngineNodeCode, componentCode)
                        .ne(EngineNodeComponentRel::getComponentCode, StringUtils.EMPTY)
                        .isNotNull(EngineNodeComponentRel::getComponentCode)
                        .eq(EngineNodeComponentRel::getComponentType, NodeTypeEnum.CHILD_ENGINE.getCode())
                        .groupBy(EngineNodeComponentRel::getEngineNodeCode));
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        //递归子引擎变量
        list.forEach(x -> {
            //当前子引擎code
            String nodeCode = x.getComponentCode();
            //查询当前引擎的全部变量并装配
            if (configVarCode(nodeCode, x.getComponentVersionNo(), varCodes)) {
                return;
            }
            recursionSuccessorVarCodes(nodeCode, varCodes);
        });
    }

    /**
     * 递归查找当前前驱引擎变量集合
     */
    private void recursionPrecursorVarCodes(String componentCode, Set<String> varCodes) {
        //查询前驱引擎
        List<EngineNodeComponentRel> list = this.list(
                new LambdaQueryWrapper<EngineNodeComponentRel>()
                        .select(EngineNodeComponentRel::getEngineNodeCode)
                        .eq(EngineNodeComponentRel::getComponentCode, componentCode)
                        .ne(EngineNodeComponentRel::getComponentCode, StringUtils.EMPTY)
                        .isNotNull(EngineNodeComponentRel::getComponentCode)
                        .eq(EngineNodeComponentRel::getComponentType, NodeTypeEnum.CHILD_ENGINE.getCode())
                        .groupBy(EngineNodeComponentRel::getEngineNodeCode));
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        //递归子引擎变量
        list.forEach(x -> {
            //当前子引擎code
            String nodeCode = x.getEngineNodeCode().substring(0, x.getEngineNodeCode().lastIndexOf(SysConstant.UNDERLINE));
            //查询当前引擎的全部变量并装配
            if (configVarCode(nodeCode, x.getComponentVersionNo(), varCodes)) {
                return;
            }
            recursionPrecursorVarCodes(nodeCode, varCodes);
        });
    }

    private boolean configVarCode(String nodeCode, Long engineVersionNo, Set<String> varCodes) {
        //查询当前子引擎上线版本
        Long id = engineVersionService.getVersionIdByStatus(nodeCode, engineVersionNo, EngineStatusEnum.DEPLOY.getStatus());
        if (Objects.isNull(id)) {
            return true;
        }
        //查询当前节点的全部变量
        List<String> fieldCodes = engineNodeService.getFieldCodesByEngineVersionId(id);
        if (!CollectionUtils.isEmpty(fieldCodes)) {
            varCodes.addAll(fieldCodes.stream().map(codes -> Sets.newHashSet(codes.split(SysConstant.COMMA)))
                    .flatMap(Set::stream).collect(Collectors.toSet()));
        }
        return false;
    }
}
